package com.github.niefy.modules.third.filter;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.github.niefy.common.utils.CookieUtil;
import com.github.niefy.common.utils.JWTUtils;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 *thirdToken过滤
 */
@Slf4j
public class ThirdTokenFilter extends HttpFilter {

    @Override
    public void init(FilterConfig config) {
    }

    //将cookie-token值解析放入request域,Controller可从request中直接取值
    @Override
    public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        Cookie[] cookies = request.getCookies();
        //放行标志,首页直接放行,首页请求处理后放行,其他静态资源及接口需要双token验证
        if (request.getRequestURI().contains("/index.html")) {
            chain.doFilter(request, response);
            return;
        }
        boolean flag = request.getRequestURI().contains("/getThirdToken")||request.getRequestURI().contains("/getThirdIdToken");
        if (flag) {
            indexTokenHandle(cookies,request,response);
            chain.doFilter(request, response);
            return;
        }
        if (checkToken(cookies,request,response)) {
            chain.doFilter(request, response);
        }else {
            response.sendRedirect("/web/index/index.html");
        }
    }

    @Override
    public void destroy() {
    }

    //校验cookie-token
    private boolean checkToken(Cookie[] cookies, HttpServletRequest request, HttpServletResponse response){
        boolean thirdTokenFlag = false;
        boolean thirdIdFlag = false;
        DecodedJWT thirdJwt;
        DecodedJWT thirdIdJwt;
        //非首页无thirdToken跳转首页
        if (null!=cookies && cookies.length > 0) {
            for(Cookie cookie : cookies){
                try {
                    if("thirdToken".equals(cookie.getName())){
                        thirdJwt = JWTUtils.verify(cookie.getValue());
                        thirdJwt.getClaims().forEach((k, v)->{
                            request.setAttribute(k, v.asString());
                        });
                        thirdTokenFlag = true;
                    }else if ("thirdId".equals(cookie.getName())){
                        thirdIdJwt = JWTUtils.verify(cookie.getValue());
                        request.setAttribute("thirdId", thirdIdJwt.getClaim("thirdId").asString());
                        thirdIdFlag = true;
                    }
                }catch (Exception e){
                    //定期更换jwt加盐密钥导致token解析失败，将无效cookie-token清除
                    CookieUtil.clearCookie(response,"thirdToken");
                    CookieUtil.clearCookie(response,"thirdId");
                    log.error(e.getMessage(),e);
                }

            }
        }
        return thirdTokenFlag && thirdIdFlag;
    }

    private void renewalToken(DecodedJWT jwtObj, HttpServletResponse response, String cookieName){
        if (JWTUtils.checkTokenExpires(jwtObj)){
            String newToken = JWTUtils.renewalToken(jwtObj);
            CookieUtil.setThirdCookie(response, cookieName, newToken);
        }
    }
    /**
     * 首页进行续签，与checkToken的区别增加了续签操作
     * */
    private void indexTokenHandle(Cookie[] cookies, HttpServletRequest request, HttpServletResponse response){
        DecodedJWT thirdJwt;
        DecodedJWT thirdIdJwt;
        if (null!=cookies && cookies.length > 0) {
            for(Cookie cookie : cookies){
                try {
                    //首页解析thirdToken用于签发thirdId-token
                    if("thirdToken".equals(cookie.getName())){
                        thirdJwt = JWTUtils.verify(cookie.getValue());
                        thirdJwt.getClaims().forEach((k, v)->{
                            request.setAttribute(k, v.asString());
                        });
                        //续签
                        renewalToken(thirdJwt, response, "thirdToken");
                    }else if ("thirdId".equals(cookie.getName())){
                        thirdIdJwt = JWTUtils.verify(cookie.getValue());
                        request.setAttribute("thirdId", thirdIdJwt.getClaim("thirdId").asString());
                        //续签
                        renewalToken(thirdIdJwt, response, "thirdId");
                    }
                }catch (Exception e){
                    //定期更换jwt加盐密钥导致token解析失败，将无效cookie-token清除
                    CookieUtil.clearCookie(response,"thirdToken");
                    CookieUtil.clearCookie(response,"thirdId");
                    log.error(e.getMessage(),e);
                }

            }
        }
    }
    /*TODO 现在token实现方式存在同时有两个token有效且旧token可续签的情况,cookie的
    *  替换并不能根本解决这个问题，使用Redis+用户指纹（与当前密码唯一对应）参与jwt
    *  签发的方式可以避免，但引入之后过于复杂暂不考虑*/
}
